package io;

import lombok.val;
import lombok.var;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;

public class BufferTest {


    public static void main(String[] args) throws IOException {


        startServer();

        startClient();

    }












    private static void startClient() {

        new Thread(() -> {

            //创建一个远程连接

            try {
                SocketChannel channel = SocketChannel.open(new InetSocketAddress("localhost", 8080));

                ByteBuffer wrap = ByteBuffer.wrap("测试".getBytes());
                channel.write(wrap);

            } catch (Exception e) {

            }

        }).start();

    }


    private static void startServer() {

        new Thread(() -> {

            try {
                System.out.println("正在启动服务端...");

                //创建一个多路复用器
                Selector selector = Selector.open();

                //开启服务端通道
                ServerSocketChannel socketChannel = ServerSocketChannel.open();

                //设置非阻塞
                socketChannel.configureBlocking(false);

                //绑定端口
                socketChannel.bind(new InetSocketAddress(8080));

                //将通道注册到多路复用器上,标记状态为accept
                SelectionKey register = socketChannel.register(selector, SelectionKey.OP_ACCEPT,new Object());

                new Thread(() -> {

                    //这个循环可以放在多个线程中进行分别处理
                    while (true) {
                        try {

                            //阻塞选择
                            //是否能够选中元素取决于注册到多路复用器上的标记
                            int select = selector.select();

                            if (select == 0) {
                                continue;
                            }

                            //返回被选中的集合
                            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();

                            while (iterator.hasNext()) {

                                //取出该元素
                                SelectionKey next = iterator.next();

                                //将当前元素移除
                                iterator.remove();

                                if (next.isValid()) {

                                    try {

                                        next.interestOps();
                                        if (next.isAcceptable()) {//当没有连接可以获取的时候不可选中

                                            System.out.println("收到连接请求");

                                            accept(next, selector);
                                        } else if (next.isReadable()) {//当没有数据可读取的时候不可选中

                                            System.out.println("有可读数据");

                                            read(next, selector);
                                        } else if (next.isWritable()) {//除非手动将通道注册为其他状态,否则该通道将一直可被选中
                                            write(next, selector);
                                        }

                                    } catch (CancelledKeyException e) {
                                        //断开连接
                                        next.cancel();
                                    }
                                }

                            }

                        } catch (Exception e) {
                            e.printStackTrace();
                            break;
                        }
                    }


                }).start();


            } catch (Exception e) {
                e.printStackTrace();
            }

        }).start();

    }

    private static void accept(SelectionKey key, Selector selector) throws Exception {
        ServerSocketChannel channel = (ServerSocketChannel) key.channel();
        SocketChannel accept = channel.accept();

        accept.configureBlocking(false);

        Object o = new Object();

        //绑定到一个对象.
        key.attach(o);

        accept.register(selector, SelectionKey.OP_WRITE, ByteBuffer.allocate(1024));

    }

    private static void write(SelectionKey key, Selector selector) throws IOException {

        SocketChannel channel = (SocketChannel) key.channel();
        ByteBuffer allocate = ByteBuffer.allocate(1024);
        allocate.put("响应".getBytes());
        allocate.flip();
        channel.write(allocate);
        key.interestOps(SelectionKey.OP_READ);

        //  key.interestOps()

        // SelectionKey register = channel.register(selector, SelectionKey.OP_READ);

    }

    //进行读取
    private static void read(SelectionKey key, Selector selector) throws Exception {

        ByteBuffer byteBuffer = (ByteBuffer) key.attachment();
        SocketChannel channel = (SocketChannel) key.channel();
        channel.read(byteBuffer);
        byteBuffer.flip();
        System.out.print(new String(byteBuffer.array()));

        //注册为可写状态
        // channel.register(selector, SelectionKey.OP_WRITE);


        //write(key, selector);

        // Object o = System.currentTimeMillis() + "";
        // key.attach(o);

        //channel.register(selector, SelectionKey.OP_WRITE);

    }


}
